﻿//-----------------------------------------------------------------------
// <copyright file="Category.cs" company="Craig Longford (deltawolf7@gmail.com)">
//     Copyright (c) Craig Longford. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Delta.Mercury.Business.Commerce
{
    using System;
    using System.Globalization;
    using Delta.Data.DataExpress;
    using Delta.Mercury.Business.Exceptions;

    /// <summary>
    /// Products category
    /// </summary>
    [Serializable]
    public class Category : IdentifierBase, IDataServicable, ICategory
    {
        #region Members
        /// <summary>
        /// Category name
        /// </summary>
        private string name;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the Category class.
        /// </summary>
        public Category()
            : this(string.Empty, 0)
        {
        }

        /// <summary>
        /// Initializes a new instance of the Category class.
        /// </summary>
        /// <param name="name">Category name</param>
        /// <param name="sortOrder">Sort order</param>
        public Category(string name, int sortOrder)
            : this(name, Guid.Empty, sortOrder)
        {
        }

        /// <summary>
        /// Initializes a new instance of the Category class.
        /// </summary>
        /// <param name="name">Category name</param>
        /// <param name="parentGuid">Parent category unique identifier</param>
        /// <param name="sortOrder">Sort order</param>
        public Category(string name, Guid parentGuid, int sortOrder)
            : base()
        {
            this.name = name;
            this.ParentGuid = parentGuid;
            this.SortOrder = sortOrder;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the category name
        /// </summary>
        public virtual string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                if (value.Length < 1)
                {
                    throw new InvalidLengthException("Category name must be a minimum of 1 characters.");
                }

                if (value.Length > 30)
                {
                    throw new InvalidLengthException("Category name must be a maximum of 30 characters.");
                }

                TextInfo info = CultureInfo.CurrentCulture.TextInfo;
                this.name = info.ToTitleCase(value);
            }
        }

        /// <summary>
        /// Gets or sets the unique identifier of the parent category
        /// </summary>
        public virtual Guid ParentGuid { get; set; }

        /// <summary>
        ///  Gets or sets the sort order of the category
        /// </summary>
        public virtual int SortOrder { get; set; }
        #endregion

        #region Static Load Method
        /// <summary>
        /// Load category from database
        /// </summary>
        /// <param name="guid">Unique identifier</param>
        /// <param name="showDeleted">Show deleted</param>
        /// <returns>Filled category</returns>
        public static Category Load(Guid guid, bool showDeleted)
        {
            Parameters parameters = new Parameters();
            parameters.Add(new Parameter("Guid", guid));
            parameters.Add(new Parameter("Deleted", showDeleted));
            return DataAccess.GetSingle<Category>("LoadCatgeory", System.Data.CommandType.StoredProcedure, parameters);
        }

        /// <summary>
        /// Load category from database
        /// </summary>
        /// <param name="name">Category name</param>
        /// <param name="showDeleted">Show deleted</param>
        /// <returns>Filled category</returns>
        public static Category Load(string name, bool showDeleted)
        {
            Parameters parameters = new Parameters();
            parameters.Add(new Parameter("Name", name));
            parameters.Add(new Parameter("Deleted", showDeleted));
            return DataAccess.GetSingle<Category>("LoadCatgeory", System.Data.CommandType.StoredProcedure, parameters);
        }
        #endregion

        #region Get Parent Methods
        /// <summary>
        /// Gets parent categories
        /// </summary>
        /// <param name="showDeleted">Show deleteed</param>
        /// <returns>Parent category</returns>
        public virtual Category GetParent(bool showDeleted)
        {
            return Category.Load(this.ParentGuid, showDeleted);
        }
        #endregion

        #region Get Child Methods
        /// <summary>
        /// Get children of the category
        /// </summary>
        /// <param name="showDeleted">Show deleted</param>
        /// <returns>Child categories</returns>
        public virtual Categories GetChildren(bool showDeleted)
        {
            return Categories.Load(this, showDeleted);
        }
        #endregion

        #region Remove Product Link Method
        /// <summary>
        /// Remove product link
        /// </summary>
        /// <param name="product">Product to detach</param>
        public virtual void RemoveProductLink(IProduct product)
        {
            Parameters parameters = new Parameters();
            parameters.Add(new Parameter("ProductGuid", product.Guid));
            parameters.Add(new Parameter("CategoryGuid", this.Guid));
            DataAccess.NonQuery("RemoveCategoryLink", System.Data.CommandType.StoredProcedure, parameters);
        }
        #endregion

        #region Add Product Link Method
        /// <summary>
        /// Add product link
        /// </summary>
        /// <param name="product">Product to attach</param>
        public virtual void AddProductLink(IProduct product)
        {
            Parameters parameters = new Parameters();
            parameters.Add(new Parameter("ProductGuid", product.Guid));
            parameters.Add(new Parameter("CategoryGuid", this.Guid));
            DataAccess.NonQuery("SaveCategoryLink", System.Data.CommandType.StoredProcedure, parameters);
        }
        #endregion

        #region Get Images
        /// <summary>
        /// Get category images
        /// </summary>
        /// <param name="showDeleted">Show deleted</param>
        /// <returns>Collection of images</returns>
        public virtual Images GetImages(bool showDeleted)
        {
            return Images.Load(this.Guid, showDeleted);
        }
        #endregion

        #region Get Products
        /// <summary>
        /// Get category products
        /// </summary>
        /// <param name="showDeleted">Show deleted</param>
        /// <returns>Product collection</returns>
        public Products GetProducts(bool showDeleted)
        {
            return Products.Load(this, showDeleted);
        }
        #endregion

        #region Save Method
        /// <summary>
        /// Save category to database
        /// </summary>
        public virtual void Save()
        {
            DataAccess.NonQuery("SaveCategory", System.Data.CommandType.StoredProcedure, GetSaveParameters());
        }
        #endregion

        #region Delete Methods
        /// <summary>
        /// Delete category from database
        /// </summary>
        public virtual void Delete()
        {
            Parameters parameters = new Parameters();
            parameters.Add(new Parameter("Guid", this.Guid));
            DataAccess.NonQuery("DeleteCategory", System.Data.CommandType.StoredProcedure, parameters);

            this.RecursiveDelete(this.GetChildren(false));
        }
        #endregion

        #region Fill Methods
        /// <summary>
        /// Fill category from database
        /// </summary>
        /// <param name="reader">Data reader</param>
        public virtual void Fill(System.Data.IDataReader reader)
        {
            this.Guid = Helper.ToGuid(reader["Guid"]);
            this.Name = Helper.ToString(reader["Name"]);
            this.ParentGuid = Helper.ToGuid(reader["ParentGuid"]);
            this.SortOrder = Helper.ToInt(reader["SortOrder"]);
        }
        #endregion

        #region Recursive Delete
        /// <summary>
        /// Recursive Delete
        /// </summary>
        /// <param name="categories">Categories to check</param>
        private void RecursiveDelete(Categories categories)
        {
            foreach (Category category in categories)
            {
                this.RecursiveDelete(category.GetChildren(false));
                category.Delete();
            }
        }
        #endregion

        #region Get Save Parameter
        /// <summary>
        /// Get save parameters
        /// </summary>
        /// <returns>Parameter collection</returns>
        public Parameters GetSaveParameters()
        {
            Parameters parameters = new Parameters();
            parameters.Add(new Parameter("Guid", this.Guid));
            parameters.Add(new Parameter("Name", this.Name));
            parameters.Add(new Parameter("ParentGuid", this.ParentGuid));
            parameters.Add(new Parameter("SortOrder", this.SortOrder));
            return parameters;
        }
        #endregion
    }
}
